﻿using Microsoft.Extensions.DependencyInjection;
using Microsoft.Win32;
using System.Collections.ObjectModel;
using System.IO;
using System.Windows;
using VIA.Foundation;
using VIA.ImageProcessing;
using VIA.Integration;
using VIA.Integration.Domain;
using VIA.Integration.Domain.Production;
using VIA.Integration.Presentation;
using VIA.Presentation;
using VIA.Presentation.Contracts;
using VIA.SiMoJi.Domain.Inspection;
using VIA.SiMoJi.Domain.Option;
using VIA.SiMoJi.Domain.Vision;
using VIA.VTPlatformService;
using VT.Framework.Designer.Flow;
using VT.Framework.Designer.Project;
using VT.Framework.Scene2D.Structs;

namespace VIA.SiMoJi.Presentation.ViewModel
{
    [ViewModel(typeof(IVisionStationOptionView))]
    internal class VisionStationOptionViewModel : EditorViewModel<IVisionStationOptionView, VisionStationOption>
    {
        private IDispatcher _dispatcher;
        private IVTPlatformManager _VTPlatformManager;
        readonly IDetectionContextFactory _detectionContextFactory;
        private IProductionLine _productionLine;
        readonly IMessageService _messageService;
        private readonly Inspector _inspector;
        private int selectedProjectID;
        private bool isLoadProjectFromFile;
        private int selectedFlow;
        private int selectedCamera;
        private CancellationTokenSource _cancellationTokenSource = new();
        ImageDetectionResult _result;
        private bool isUseSiMo1 = true;
        private bool isAutoSave;
        private bool isCalibrationEnable;

        public IRelayCommand CancelCommand { get; set; }
        public IRelayCommand EditorCommand { get; set; }
        public IRelayCommand SelectCommand { get; set; }
        public IRelayCommand RunCommand { get; set; }
        public IRelayCommand SelectFileCommand { get; set; }
        public IRelayCommand TopCameraMatrixCalibrationCommand { get; set; }
        public IRelayCommand BottomCameraMarkCalibrateCommand { get; set; }
        public IRelayCommand FlyCaptureReadyCommand { get; set; }
        public IRelayCommand ClearFlyCaptureCommand { get; set; }
        public IRelayCommand SnapCommand { get; set; }
        public IRelayCommand RotationCenterCalibrateCommand { get; set; }
        public IRelayCommand TopCameraMarkCaptureCommand { get; set; }

        public IRelayCommand SaveUpCommandImage { get; }
        public bool IsLoadProjectFromFile { get => isLoadProjectFromFile; set { SetProperty(ref isLoadProjectFromFile, value); } }
        public int SelectedProjectID { get => selectedProjectID; set { SetProperty(ref selectedProjectID, value); } }
        public ObservableCollection<string> FlowNames { get; set; } = new();
        public int SelectedFlow { get => selectedFlow; set => SetProperty(ref selectedFlow, value); }
        public int SelectedCamera { get => selectedCamera; set => SetProperty(ref selectedCamera, value); }
        public bool IsUseSiMo1 { get => isUseSiMo1; set => SetProperty(ref isUseSiMo1, value); }
        int _selecteOfflineFlowIndex;
        public int SelecteOfflineFlowIndex
        {
            get => _selecteOfflineFlowIndex;
            set => SetProperty(ref _selecteOfflineFlowIndex, value);
        }

        public ImageDetectionResult Result
        {
            get => _result;
            set => SetProperty(ref _result, value);
        }
        public bool IsAutoSave { get => isAutoSave; set => SetProperty(ref isAutoSave, value); }
        public bool IsCalibrationEnable { get => isCalibrationEnable; set => SetProperty(ref isCalibrationEnable, value); }
        public IRelayCommand OfflineLoadImageCommand { get; }
        public VisionStationOptionViewModel(IServiceProvider service, Inspector inspector) : base(service)
        {
            this._inspector = inspector;
            _dispatcher = service.GetRequiredService<IDispatcher>();
            _VTPlatformManager = service.GetRequiredService<IVTPlatformManager>();
            _detectionContextFactory = service.GetRequiredService<IDetectionContextFactory>();
            _productionLine = service.GetRequiredService<IProductionLine>();
            _productionLine.ImageDetectionResult += ProductionLine_ImageDetectionResult;
            _messageService = _service.GetService<IMessageService>();
            EditorCommand = _commandFactory.Create(Edit);
            SelectCommand = _commandFactory.Create(Select);
            RunCommand = _commandFactory.Create(Run);
            SelectFileCommand = _commandFactory.Create(SelectFile);
            CancelCommand = _commandFactory.Create(Cancel);
            FlyCaptureReadyCommand = _commandFactory.Create(FlyCaptureReady);
            SnapCommand = _commandFactory.Create(Snap);
            ClearFlyCaptureCommand = _commandFactory.Create(ClearFlyCapture);
            TopCameraMarkCaptureCommand = _commandFactory.Create(TopCameraMarkCapture);
            TopCameraMatrixCalibrationCommand = _commandFactory.Create(TopCameraMatrixCalibration);
            RotationCenterCalibrateCommand = _commandFactory.Create(BottomCameraRotationCenterCalibrate);
            BottomCameraMarkCalibrateCommand = _commandFactory.Create(BottomCameraMarkCalibrate);
            OfflineLoadImageCommand = _commandFactory.Create(OfflineLoadImage);
        }

        private async Task Snap()
        {
            if (SelectedCamera == 0)
            {
                await _inspector.VisionStation.TopCapture();
            }
            if (SelectedCamera == 1)
            {
                await _inspector.VisionStation.UpSnap(IsUseSiMo1);
            }
            if (SelectedCamera == 2)
            {
                await _inspector.VisionStation.BottomSnap();
            }
        }

        private async void TopCameraMatrixCalibration()
        {
            _cancellationTokenSource?.Cancel();
            _cancellationTokenSource = new CancellationTokenSource();
            await _inspector.VisionStation.TopCalibration(IsAutoSave, _cancellationTokenSource.Token);
            Option = _currentRecipe.Get<VisionStationOption>(this.EditObject.Id);
            this.RaisePropertyChanged(nameof(Option));
        }

        private async void TopCameraMarkCapture()
        {
            await _inspector.VisionStation.TopMarkCapture(IsAutoSave);
        }

        private async Task BottomCameraRotationCenterCalibrate()
        {
            _cancellationTokenSource?.Cancel();
            _cancellationTokenSource = new CancellationTokenSource();
            await _inspector.BanYunStation.BottomCameraRotationCenterCalibration(IsUseSiMo1, _cancellationTokenSource.Token, IsAutoSave, true);
            RaisePropertyChanged(nameof(Option));
        }

        private async void BottomCameraMarkCalibrate()
        {
            _cancellationTokenSource?.Cancel();
            _cancellationTokenSource = new CancellationTokenSource();
            await _inspector.BanYunStation.BottomCameraRotationCenterCalibration(IsUseSiMo1, _cancellationTokenSource.Token, IsAutoSave, false);
        }

        private async void ClearFlyCapture()
        {
            await _inspector.VisionStation.PrepearBottomFlyCapture(VisionStation.CaptureFlag.DuiWei_0, IsUseSiMo1, 1, $"{DateTime.Now:HHmmss}");
            _inspector.BanYunStation.ClearFlyCapture();
        }

        private void FlyCaptureReady()
        {
            _inspector.BanYunStation.SetFlyCapture();
        }

        private void ProductionLine_ImageDetectionResult(object? sender, (string name, ImageDetectionResult result) e)
        {
            Result = e.result;
        }

        private void Select()
        {
            OpenFileDialog dialog = new OpenFileDialog();
            dialog.Title = "选择工程文件路径";
            dialog.DefaultExt = ".vtproj";
            dialog.Filter = "算法工程文件|*.vtproj";
            if (dialog.ShowDialog(Application.Current.MainWindow) == true)
            {
                Option.ProjectFilePath = dialog.FileName;
                _VTPlatformManager.ClearCache();
                _VTPlatformManager.LoadProject(Option.ProjectFilePath, Option.ConcurrentLevel);
                var p = _VTPlatformManager.GetProject(Option.ProjectFilePath, SelectedProjectID);
                if (p != null)
                {
                    FlowNames.Clear();
                    foreach (var item in p.FlowList)
                    {
                        FlowNames.Add(item.Name);
                    }
                }
            }
        }

        private void SelectFile()
        {
            OpenFileDialog dialog = new OpenFileDialog();
            dialog.Title = "选择图片";
            dialog.DefaultExt = ".png";
            dialog.Filter = "BMP|*.bmp|PNG|*.png";
            if (dialog.ShowDialog(Application.Current.MainWindow) == true)
            {
                Option.SelectedFile = dialog.FileName;
            }
        }

        private void Edit()
        {
            try
            {
                if (Option == null || Option.ProjectFilePath.IsNullOrEmpty())
                    return;
                VTProject p = new();
                if (!IsLoadProjectFromFile)
                {
                    if (_VTPlatformManager.GetCacheProjectInfo().Count == 0)
                        _VTPlatformManager.LoadProject(Option.ProjectFilePath, 1);
                    p = _VTPlatformManager.GetProject(Option.ProjectFilePath, SelectedProjectID);
                }
                else
                {
                    p.LoadAs(Option.ProjectFilePath);
                }
                if (p != null)
                {
                    p.Edit();
                    _VTPlatformManager.ClearCache();
                    _VTPlatformManager.LoadProject(Option.ProjectFilePath, Option.ConcurrentLevel);
                }
                else
                {
                    MessageBox.Show("加载工程失败：工程路径不存在，或工程索引不存在(最大索引 = 工程数量 - 1 )。");
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);
            }
        }

        private void Run()
        {
            try
            {
                ImageData image = new(Option.SelectedFile);
                var context = _detectionContextFactory.Create(() =>
                {
                    var result = new AlgorithmResult();
                    using var blockWrapper = _VTPlatformManager.GetBlockWrapper(Option.ProjectFilePath, SelectedFlow);
                    var block = blockWrapper?.VTFlowBlock;
                    if (block == null) return result;
                    block.Inputs["In"].Value = image.ToVImage8Grey();
                    block.Run();
                    if (block.Status.Result == ERunResultType.Success)
                    {
                        double rs = 1;
                        if (block.TryGetResult("resolution", out double resolution))
                        {
                            rs = resolution;
                        }
                        if (block.TryGetResult("x", out double x))
                        {
                            result.AddMessage($"X: {rs * x:F3}", Quality.Ok);
                        }
                        if (block.TryGetResult("y", out double y))
                        {
                            result.AddMessage($"Y: {rs * y:F3}", Quality.Ok);
                        }
                        if (block.TryGetResult("cross", out VPoint cross))
                        {
                            result.AddMessage($"X: {rs * cross.X:F3}mm", Quality.Ok);
                            result.AddMessage($"Y: {rs * cross.Y:F3}mm", Quality.Ok);
                        }
                        if (block.TryGetResult("dist1", out double dist1))
                        {
                            result.AddMessage($"X: {rs * dist1:F3}mm", Quality.Ok);
                        }
                        if (block.TryGetResult("dist2", out double dist2))
                        {
                            result.AddMessage($"Y: {rs * dist2:F3}mm", Quality.Ok);
                        }
                        if (block.TryGetResult("angle", out double angle))
                        {
                            result.AddMessage($"Angle: {angle:F3}", Quality.Ok);
                        }
                        if (block.TryGetResult("line1", out VLine line1))
                        {
                            result.AddStroke(new DrawableLine(line1.ToVIALine()) { Stroke = System.Drawing.Color.Green, StrokeThickness = 2 });
                        }
                        if (block.TryGetResult("line2", out VLine line2))
                        {
                            result.AddStroke(new DrawableLine(line2.ToVIALine()) { Stroke = System.Drawing.Color.Green, StrokeThickness = 2 });
                        }
                        if (block.TryGetResult("line3", out VLine line3))
                        {
                            result.AddStroke(new DrawableLine(line3.ToVIALine()) { Stroke = System.Drawing.Color.Green, StrokeThickness = 2 });
                        }
                        if (block.TryGetResult("line4", out VLine line4))
                        {
                            result.AddStroke(new DrawableLine(line4.ToVIALine()) { Stroke = System.Drawing.Color.Green, StrokeThickness = 2 });
                        }
                    }
                    else
                    {
                        result.AddMessage($"运行失败:{block.Status.ErrorMessage}");
                    }
                    return result;
                });
                Result = new ImageDetectionResult(image, context);
                //_productionLine.OnImageDetectionResult("", Result);
            }
            catch (Exception)
            {
                throw;
            }
        }

        protected override void OnEditObjectChanged(IObject oldObject, IObject newObject)
        {
            if (oldObject != newObject)
            {
                var p = _VTPlatformManager.GetProject(Option.ProjectFilePath, SelectedProjectID);
                if (p != null)
                {
                    FlowNames.Clear();
                    foreach (var item in p.FlowList)
                    {
                        FlowNames.Add(item.Name);
                    }
                }
            }
        }

        protected override void OnViewLoaded()
        {
            _inspector.VisionStation.InitCamera();
            if (_VTPlatformManager.GetCacheProjectInfo().Count == 0)
            {
                _VTPlatformManager.LoadProject(Option.ProjectFilePath, 1);
                var p = _VTPlatformManager.GetProject(Option.ProjectFilePath, SelectedProjectID);
                if (p != null)
                {
                    FlowNames.Clear();
                    foreach (var item in p.FlowList)
                    {
                        FlowNames.Add(item.Name);
                    }
                }
            }
        }

        private void Cancel()
        {
            Option = _currentRecipe.Get<VisionStationOption>(EditObject.Id);
        }
        async void OfflineLoadImage()
        {
            try
            {
                var fileDialogService = _service.GetService<IFileDialogService>();
                var filePath = fileDialogService.ShowOpenFileDialog(View, [new FileType("图片", ".png"), new FileType("图片", ".*"),]);
                if (!filePath.IsNullOrEmpty())
                {
                    var image = ImageData.Read(filePath);
                    var result = new AlgorithmResult();
                    using var blockWrapper = _VTPlatformManager.GetBlockWrapper(Option.ProjectFilePath, SelecteOfflineFlowIndex);
                    var block = blockWrapper?.VTFlowBlock;
                    if (block == null) return;
                    block.Inputs["In"].Value = image.ToVImage8Grey();
                    block.Run();

                    //var imageDetecter = _service.GetService<IImageDetecter>();
                    //var productionLine = _service.GetService<Inspector>().VisionStation.ProductionLine;
                    //var option = _service.GetService<Inspector>().VisionStation.Option;
                    //_ = productionLine.AddTopImage(image, null, option.Top_Camera_CaptureFlowBlock1, option);

                    //#region TODO 顶部相机测试流程
                    //List<bool> hasProducts = (List<bool>)block.Outputs["hasProducts"].Value;
                    //List<string> allResultsString = (List<string>)block.Outputs["AllResultsString"].Value;
                    //var tempHasProducts = new bool[hasProducts.Count()];
                    //for (int i = 0; i < allResultsString.Count(); i++)//84到1
                    //{
                    //    string resultName = allResultsString[i];
                    //    var number = Convert.ToInt32(resultName.Replace("灰度信息", string.Empty));
                    //    tempHasProducts[number - 1] = hasProducts[i];
                    //}
                    //int frontCount = 0;
                    //int backCount = 0;
                    //var allSideResults = new List<bool>();
                    //if (block.Outputs.ContainsKey("AllSideResults"))
                    //{
                    //    allSideResults = ((List<bool>)block.Outputs["AllSideResults"].Value);
                    //}
                    //if (block.Outputs.ContainsKey("Front"))
                    //{
                    //    frontCount = ((List<VCoord>)block.Outputs["Front"].Value).Count();
                    //}
                    //if (block.Outputs.ContainsKey("Back"))
                    //{
                    //    backCount = ((List<VCoord>)block.Outputs["Back"].Value).Count();
                    //}
                    //List<bool> fronts = new List<bool>();//正方向
                    //List<bool> backs = new List<bool>();
                    //List<string> strings1 = new List<string>();
                    //List<string> strings2 = new List<string>();
                    //for (int i = 0; i < tempHasProducts.Count(); i++)
                    //{
                    //    if ((i >= 0 && i <= 6) || (i >= 14 && i <= 20) || (i >= 28 && i <= 34) || (i >= 42 && i <= 48) || (i >= 56 && i <= 62) || (i >= 70 && i <= 76))
                    //    {
                    //        fronts.Add(tempHasProducts[i]);
                    //        strings1.Add(i.ToString());
                    //    }
                    //    else if ((i >= 7 && i <= 13) || (i >= 21 && i <= 27) || (i >= 35 && i <= 41) || (i >= 49 && i <= 55) || (i >= 63 && i <= 69) || (i >= 77 && i <= 83))
                    //    {
                    //        backs.Add(tempHasProducts[i]);
                    //        strings2.Add(i.ToString());
                    //    }
                    //}
                    ////正方向（第一排这种）全图匹配到的正方向产品数量，如果zheng=42-正方向空穴数量，则正常，若不等则异常。
                    //var frontNoneCount = (42 - fronts.Count(x => x == false));
                    //if (frontCount != frontNoneCount)
                    //{
                    //    result.AddMessage($"产品正数量异常", Quality.Ng);
                    //}
                    //else
                    //{
                    //    result.AddMessage($"产品正数量{frontCount}", Quality.Ok);
                    //}
                    ////反方向（第二排这种）全图匹配到的反方向产品数量，如果zheng=42-反方向空穴数量，则正常，若不等则异常。
                    //var backNoneCount = (42 - backs.Count(x => x == false));
                    //if (backCount != backNoneCount)
                    //{
                    //    result.AddMessage($"产品反方向异常", Quality.Ng);
                    //}
                    //else
                    //{
                    //    result.AddMessage($"产品反方向数量{backCount}", Quality.Ok);
                    //}
                    ////满料Tary拍照得到产品灰度在 a 以下，空Tary拍照得到产品灰度在 b 以上，对比正常流程检测时84个穴位灰度，如果有穴位  a<灰度<b，则异常。
                    //if (allSideResults.Any(x => x))
                    //{
                    //    result.AddMessage("产品定位异常", Quality.Ng);
                    //}
                    //#endregion
                }
            }
            catch (Exception ex)
            {
                _messageService.ShowError(View, $"{ex.Message}");
            }
        }
    }
}
